﻿using CommunityToolkit.Mvvm.ComponentModel;
using Koala.Pro.Common;
using Koala.Pro.Core;
using Koala.Pro.Models;
using Koala.Pro.Services;
using Koala.Pro.ViewModels;
using Koala.Pro.Views;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
using System.Data;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using Wpf.Ui;

namespace Koala.Pro
{
    public partial class App : Application
    {
        private static readonly IHost _host = Host.CreateDefaultBuilder().ConfigureAppConfiguration(delegate (IConfigurationBuilder builder)
        {
            builder.SetBasePath(Path.GetDirectoryName(AppContext.BaseDirectory));
        }).ConfigureServices(delegate (HostBuilderContext context, IServiceCollection services)
        {
            services.AddHostedService<ApplicationHostService>();
            ServiceCollectionServiceExtensions.AddSingleton<IPageService, PageService>(services);
            ServiceCollectionServiceExtensions.AddSingleton<IWindowsProviderService, WindowsProviderService>(services);
            ServiceCollectionServiceExtensions.AddSingleton<IThemeService, ThemeService>(services);
            ServiceCollectionServiceExtensions.AddSingleton<ITaskBarService, TaskBarService>(services);
            ServiceCollectionServiceExtensions.AddSingleton<INavigationService, NavigationService>(services);
            ServiceCollectionServiceExtensions.AddSingleton<INavigationWindow, MainWindow>(services);
            ServiceCollectionServiceExtensions.AddSingleton<MainWindowViewModel>(services);
            
            IEnumerable<Type> source = Assembly.GetExecutingAssembly().DefinedTypes.Select((TypeInfo type) => type.AsType());
            Type viewPageBaseType = typeof(Page);
            var pages = (from x in source
                         where x != viewPageBaseType && viewPageBaseType.IsAssignableFrom(x)
                         where x.IsClass && !x.IsAbstract
                         select x).ToList();
            foreach (Type item in pages)
            {
                ServiceCollectionServiceExtensions.AddScoped(services, item);
            }

            Type viewModelBaseType = typeof(ObservableObject);
            var viewModelList = (from x in source
                                 where x != viewModelBaseType && viewModelBaseType.IsAssignableFrom(x)
                                 where x.IsClass && !x.IsAbstract
                                 select x).ToList();
            foreach (Type item2 in viewModelList)
            {
                ServiceCollectionServiceExtensions.AddScoped(services, item2);
            }

            Type windowBaseType = typeof(Window);
            var windows = (from x in source
                           where x != windowBaseType && windowBaseType.IsAssignableFrom(x)
                           where x.IsClass && !x.IsAbstract
                           select x).ToList();
            foreach (Type item3 in windows)
            {
                ServiceCollectionServiceExtensions.AddTransient(services, item3);
            }

            services.Configure<Models.AppConfig>(context.Configuration.GetSection("AppConfig"));
            ServiceInjection.ConfigureRepository(services);
            
            ServiceCollectionServiceExtensions.AddSingleton<IApiUserSession, ApiUserPrincipal>(services);
            //ServiceCollectionServiceExtensions.AddSingleton<IMongoDBContext, MongoDBContext>(services);
            //services.Configure<UploadSettingOptions>(context.Configuration.GetSection("UploadSettingOptions"));
            //services.Configure<Mongosettings>(context.Configuration.GetSection("MongoSettings"));
            services.AddMemoryCache();

            ServiceLocator.ConfigService(services.BuildServiceProvider());
            Log.Logger = new LoggerConfiguration().MinimumLevel.Debug().MinimumLevel.Override("Microsoft", LogEventLevel.Error).Enrich.FromLogContext().WriteTo.Console().WriteTo.File("logs/log.txt", LogEventLevel.Verbose, "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}", null, 1073741824L, null, buffered: false, shared: false, null, RollingInterval.Day, rollOnFileSizeLimit: false, 31).CreateLogger();
           
        })
        .Build();

        public static MainWindowViewModel? ViewModel
        {
            get
            {
                return GetService<MainWindowViewModel>();
            }
        }
       
        public static T? GetService<T>() where T : class
        {
            return _host.Services.GetService(typeof(T)) as T;
        }

        private async void App_OnStartup(object sender, StartupEventArgs e)
        {
            //System.NotSupportedException:“No data is available for encoding 1252. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.”
            EncodingProvider provider = CodePagesEncodingProvider.Instance;
            Encoding.RegisterProvider(provider);

            CultureInfo cultureInfo = new CultureInfo("zh-CN");
            Thread.CurrentThread.CurrentCulture = cultureInfo;
            Thread.CurrentThread.CurrentUICulture = cultureInfo;
            Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
            bool? flag = GetService<LoginView>().ShowDialog();
            if (flag.HasValue && flag.Value)
            {
                await _host.StartAsync();
                Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
            }
            else
            {
                Shutdown();
            }
        }

        private async void App_OnExit(object sender, ExitEventArgs e)
        {
            await _host.StopAsync();
            _host.Dispose();
        }

        private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            e.Handled = true;
        }
    }

}
